iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
Modern Web

重新認識Vue 走過路過不要錯過系列 第 23 篇

Vue 走過路過不要錯過 Day 23 - Vue Router 基礎,路由設定、動態參數與查詢參數

  • 分享至 

  • xImage
  •  

先想一想

  1. 瀏覽器發請求時,會把網址的哪一部分傳給伺服器?http://example.com/user/1#profile 裡,你覺得 #profile 會被傳出去嗎?
  2. 如果網址是 /user/1,使用者直接在瀏覽器按重新整理,伺服器會收到什麼?它找得到對應的檔案嗎?
  3. 商品列表的篩選條件,應該存在元件的 ref 裡,還是網址裡?如果把網址分享給朋友,畫面要能還原,這會影響你的選擇。

設定路由與動態參數

Vue Router 讓不同網址對應到不同元件。/user/:id 裡的 :id 是動態參數,/user/1、/user/2 會使用同一個元件,只有資料不同。

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import UserDetail from '../views/UserDetail.vue'
 
const routes = [
  { path: '/', component: Home },
  { path: '/user/:id', component: UserDetail }, // :id 是動態參數
]
 
const router = createRouter({
  history: createWebHistory(),
  routes,
})
 
export default router
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
 
createApp(App).use(router).mount('#app')

導覽連結用 RouterLink,對應的元件顯示在 RouterView 裡。這部分寫在 App.vue 的 template 中:

// App.vue 的 template 部分,寫成 template 字串示意
// <nav>
//   <RouterLink to="/">首頁</RouterLink>
//   <RouterLink to="/user/1">使用者 1</RouterLink>
// </nav>
// <RouterView />

在 UserDetail.vue 裡用 useRoute() 讀取參數:

// UserDetail.vue 的 script setup 部分
import { computed } from 'vue'
import { useRoute } from 'vue-router'
 
const route = useRoute()
 
// route.params.id 是字串,例如 '1'
// 用 computed 包起來,從 /user/1 切到 /user/2 時會自動更新
const userId = computed(() => route.params.id)

這裡有一個容易忽略的地方:路由參數的值都是字串。需要數字時用 Number(route.params.id) 轉換。另外,從 /user/1 切到 /user/2 時,元件不會重新建立,所以要用 computed 或 watch 來響應變化。

Hash 模式與 Web 模式

兩種模式都能讓網址改變時頁面不重新載入,差別在網址長相,以及伺服器要做的事。

Hash 模式 Web(History)模式
網址範例 /#/user/1 /user/1
建立方式 createWebHashHistory() createWebHistory()
伺服器設定 不需要 需要
SEO 較不利 較有利

Hash 模式:# 後面的內容瀏覽器不會傳給伺服器,伺服器只會收到 /,因此直接回傳 index.html。之後由 Vue Router 讀取 # 後面的路徑,決定顯示哪個元件。

import { createRouter, createWebHashHistory } from 'vue-router'
 
const router = createRouter({
  history: createWebHashHistory(),
  routes,
})

Web 模式:網址是乾淨的 /user/1,但它是真的路徑。使用者直接輸入網址或重新整理時,瀏覽器會向伺服器請求 /user/1。如果伺服器找不到對應檔案,就會回傳 404,所以部署時要設定:不管路徑是什麼,都回傳 index.html。

import { createRouter, createWebHistory } from 'vue-router'
 
const router = createRouter({
  history: createWebHistory(),
  routes,
})

怎麼選?

  • 部署在 GitHub Pages 這類靜態主機,又不方便改伺服器設定:用 Hash 模式。
  • 正式專案、需要乾淨網址與 SEO:用 Web 模式,並設定伺服器回傳 index.html。
  • 開發時用 Vite 的本地伺服器,Web 模式通常直接可用,問題多半出現在部署之後。

查詢參數:用網址記錄篩選與分頁

?page=0&sortBy=ctime 叫做查詢參數(query string)。它不影響使用哪個路由,只是附加在網址後面的資料。

  • ? 之後開始是查詢參數
  • & 分隔多組參數
  • = 左邊是 key,右邊是 value,value 永遠是字串
    原生 JS 可以用 URLSearchParams 解析:
const params = new URLSearchParams('page=0&sortBy=ctime')
params.get('page')   // '0'
params.get('sortBy') // 'ctime'

把篩選條件放在網址裡的好處是,網址就是唯一的資料來源。使用者重新整理頁面,或把網址分享給別人,畫面都能還原。

下面是商品列表的範例,過濾條件和分頁都從 route.query 讀取,修改時則用 router.push:

// ProductList.vue 的 script setup 部分
import { computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
 
const route = useRoute()
const router = useRouter()
 
// 從網址讀取,值都是字串,需要轉換
const page = computed(() => Number(route.query.page ?? 0))
const sortBy = computed(() => route.query.sortBy ?? 'ctime')
 
// 改變排序:改網址,頁數重設為 0
function changeSort(value) {
  router.push({
    query: { ...route.query, sortBy: value, page: 0 },
  })
}
 
// 換頁:只改 page,保留其他條件
function changePage(p) {
  router.push({
    query: { ...route.query, page: p },
  })
}
 
function fetchProducts() {
  // 這裡換成你的 API,用 page.value 和 sortBy.value 帶參數
  console.log('取得商品', page.value, sortBy.value)
}
 
// 網址變化時重新取資料,immediate 讓進入頁面時先執行一次
watch(() => route.query, fetchProducts, { immediate: true })

模板部分的寫法一樣直接,綁定 sortBy 與分頁按鈕即可。

這裡有幾個重點:

  • 網址是資料來源,元件只負責讀取與修改它。
  • 改過濾條件時,通常把 page 重設為 0,避免停在不存在的頁數。
  • 若不希望每次篩選都增加一筆瀏覽歷史,可以把 router.push 換成 router.replace。

小結

  • 動態參數 :id 讓同一個元件對應多個網址,參數是字串,變化時要用 computed 或 watch 響應。
  • Hash 模式不需要伺服器設定,Web 模式網址更乾淨,但部署時要讓伺服器回傳 index.html。
  • 查詢參數適合存放篩選與分頁狀態,讓網址成為唯一的資料來源,重新整理與分享都能還原畫面。

上一篇
Vue 走過路過不要錯過 Day22 - 串接 API:loading、error、資料三種狀態怎麼管
下一篇
Vue 走過路過不要錯過 Day24 - Vue Router 進階實作,導航守衛與路由懶載入
系列文
重新認識Vue 走過路過不要錯過 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言